Samsung TV can't be turn off after idle period#14587
Samsung TV can't be turn off after idle period#14587balloob merged 1 commit intohome-assistant:devfrom
Conversation
| return | ||
| try: | ||
| self.get_remote().control(key) | ||
| with self.get_remote() as remote: |
There was a problem hiding this comment.
Creating and closing a new connection for every key seems expensive. Why not retry the command with a new connection if we get a ConnectionClosed ?
There was a problem hiding this comment.
Hmm, in my mind the overhead of establishing a TCP new connection should be negligible in this usage scenario. If the control() function is called in a tight loop then the connection should definitely not be recreated on every iteration. I checked out some other components in HA and I don't see any that maintain persistent connection to the host—which makes sense to me.
Other reasons for switching to short-live connection:
samsungctlis not thread safe. Since this component can be run from different worker thread it could cause unexpected behavior if the connection is shared.- Not having to maintain another state makes the implementation simpler and reduce testing surface.
- Based on my testing (which is very limited as I only have one TV model), it takes less than one or two minutes for a connection to get closed. This means that in real-life scenario where the component does not get triggered every few second, the connection will need to be re-established every time anyway.
I'm still new to HA and Python so please correct me if I'm wrong on any point and if there is anything that I miss.
There was a problem hiding this comment.
I think the thread safe argument is an argument in favor of reusing the connection. Otherwise we might end up opening a ton of connections at the same time and overwhelm the TV.
Using WebSockets heartbeat feature, it should be pretty quick to detect a closed connection and reconnect right away.
There was a problem hiding this comment.
Thread safety is an issue with reusing the connection. When sending multiple commands consecutively—like pressing volume up multiple times, a common scenario—there could be multiple workers sending/receiving data using the same connection at the same time which could be a problem. I believe the root cause for having this catch for BorkenPipeError is because of this issue.
While it's possible to overwhelm to TV with large number of open connection at a given time, it is less likely to happen in real life as the number is limited by number of worker threads as well as the fact that these short-live connections will finish relatively quickly.
Do you mind sharing why you're particular about having this component using long-live connection, despite this is not the pattern implemented by other components? I might be missing something that you are seeing or know and just want to understand that's all.
There was a problem hiding this comment.
I am not sure where the notion comes from that other components do this. Any component that has a (web)socket connection, will keep it open. Chromecast, Cloud, Tradfri, …
There was a problem hiding this comment.
It should be fairly simple to have a method sendCommand:
- if closed or never opened, open connection
- try sending command
- if we get broken pipe error or other exception, set connection to None and call
sendCommandagain ?
There was a problem hiding this comment.
There is also a case where there is no exception raised from connection but TV won't respond. In this case we won't know whether the command succeeded or not.
I found the issue within samsungctl and working on a way to fix it.
There was a problem hiding this comment.
Sorry, I forgot that the fixes for the two issues are independent to each other. I'm updating this PR with the fix for turn_off issue. The fix in samsungctl for the no response issue can come in later.
When Samsung TV is idle for a period of time after issued a command, subsequent 'turn_off' command won't turn off the TV. The issue is seen in Samsung models with websocket as discussed in home-assistant#12302. == Reproducible Steps 1. Turn on TV (either via HA or directly). 2. Issue some commands e.g. volume ups / downs. 3. Wait for ~1 minute. 4. Issue turn_off command via HA. TV won't turn off. 5. Issue subsequent turn off commands won't turn off TV still. 6. However, issue some other commands e.g. volume ups / downs multiple times in a row and then turn_off will turn off the TV. == Root Cause The underlying websocket connection opened by samsungctl get closed after some idle time. There was no retry mechanism so issued commands would intermittently fail but the subsequent one would succeed when `_remote` get recreated. With `turn_off()`, however, there is an additional call to `self.get_remote().close()` which indirectly caused new connection to be created and then closed immediately. This causes the component to stuck in failure mode when turn_off command is repeatly issued. == The Fix Recreate the connection and retry the command if connection is closed to avoid silent failures due to connection closed. Also set `_remote` to None after calling close() to put it in correct state. This fix eliminates intermittent command failure and failure mode in turn_off().
11c3f31 to
58a1c38
Compare
When Samsung TV is idle for a period of time after issued a command, subsequent 'turn_off' command won't turn off the TV. The issue is seen in Samsung models with websocket as discussed in home-assistant#12302. == Reproducible Steps 1. Turn on TV (either via HA or directly). 2. Issue some commands e.g. volume ups / downs. 3. Wait for ~1 minute. 4. Issue turn_off command via HA. TV won't turn off. 5. Issue subsequent turn off commands won't turn off TV still. 6. However, issue some other commands e.g. volume ups / downs multiple times in a row and then turn_off will turn off the TV. == Root Cause The underlying websocket connection opened by samsungctl get closed after some idle time. There was no retry mechanism so issued commands would intermittently fail but the subsequent one would succeed when `_remote` get recreated. With `turn_off()`, however, there is an additional call to `self.get_remote().close()` which indirectly caused new connection to be created and then closed immediately. This causes the component to stuck in failure mode when turn_off command is repeatly issued. == The Fix Recreate the connection and retry the command if connection is closed to avoid silent failures due to connection closed. Also set `_remote` to None after calling close() to put it in correct state. This fix eliminates intermittent command failure and failure mode in turn_off().
Description:
When Samsung TV is idle for a period of time after issued a command,
subsequent 'turn_off' command won't turn off the TV. The issue is seen
in Samsung models with websocket as discussed in #12302.
Detailed explanation of the root cause and fix is in the commit message.
Related issue (if applicable): fixes #12302
Checklist:
tox. Your PR cannot be merged unless tests pass